<!-- 图片上传组件 -->
<template>
	<el-upload
		v-model:file-list="fileList"
		list-type="picture-card"
		:class="fileList.length >= props.limit || !props.showUploadBtn ? 'hide' : 'show'"
		:before-upload="handleBeforeUpload"
		:action="props.action"
		:headers="props.headers"
		:data="props.data"
		:name="props.name"
		:on-success="handleSuccessFile"
		:on-error="handleError"
		:accept="props.accept"
		:limit="props.limit"
	>
		<el-icon :size="24">
			<ele-Plus />
		</el-icon>
		<template #file="{ file }">
			<div style="width: 100%">
				<img class="el-upload-list__item-thumbnail" :src="file.url" alt="" />
				<span class="el-upload-list__item-actions">
					<span class="el-upload-list__item-preview" @click="previewImg(file)">
						<el-icon><ele-ZoomIn /></el-icon>
					</span>
					<span v-if="props.showDelBtn" class="el-upload-list__item-delete" @click="handleRemove(file)">
						<el-icon><ele-Delete /></el-icon>
					</span>
				</span>
			</div>
		</template>
	</el-upload>

	<el-image-viewer v-if="viewVisible" :zoom-rate="1.2" @close="closePreview" :initialIndex="initialIndex" :url-list="viewFileList" />
</template>
  <script setup lang="ts">
import { UploadRawFile, UploadRequestOptions, UploadUserFile, UploadFile, UploadProps, ElMessage } from 'element-plus';
import { Local } from '/@/utils/storage';
import { ref, watch } from 'vue';
const emit = defineEmits(['update:modelValue']);

const props = defineProps({
	/**
	 * 文件路径集合
	 */
	modelValue: {
		type: Array<string>,
		default: () => [],
	},
	/**
	 * 上传地址
	 */
	action: {
		type: String,
		default: import.meta.env.VITE_API_URL + '/xj-member/box/boxFileUpload',
	},
	/**
	 * 请求头
	 */
	headers: {
		type: Object,
		default: () => {
			return {
				Authorization: Local.get('token'),
			};
		},
	},
	/**
	 * 请求携带的额外参数
	 */
	data: {
		type: Object,
		default: () => {
			return {};
		},
	},
	/**
	 * 上传文件的参数名
	 */
	name: {
		type: String,
		default: 'file',
	},
	/**
	 * 文件上传数量限制
	 */
	limit: {
		type: Number,
		default: 10,
	},
	/**
	 * 是否显示删除按钮
	 */
	showDelBtn: {
		type: Boolean,
		default: true,
	},
	/**
	 * 是否显示上传按钮
	 */
	showUploadBtn: {
		type: Boolean,
		default: true,
	},
	/**
	 * 单张图片最大大小
	 */
	uploadMaxSize: {
		type: Number,
		default: 2 * 1024 * 1024,
	},
	/**
	 * 上传文件类型
	 */
	accept: {
		type: String,
		default: 'image/*',
	},
});

const viewVisible = ref(false);
const initialIndex = ref(0);

const fileList = ref([] as UploadUserFile[]);
const valFileList = ref([] as string[]);
const viewFileList = ref([] as string[]);

watch(
	() => props.modelValue,
	(newVal: string[]) => {
		const filePaths = fileList.value.map((file) => file.url);
		// 监听modelValue文件集合值未变化时，跳过赋值
		if (
			filePaths.length > 0 &&
			filePaths.length === newVal.length &&
			filePaths.every((x) => newVal.some((y) => y === x)) &&
			newVal.every((y) => filePaths.some((x) => x === y))
		) {
			return;
		}

		if (newVal.length <= 0) {
			fileList.value = [];
			return;
		}

		fileList.value = newVal.map((filePath) => {
			return { url: filePath } as UploadUserFile;
		});
		valFileList.value = newVal.map((filePath) => {
			return filePath;
		});
	},
	{ immediate: true }
);

/**
 * 上传成功回调
 *
 * @param options
 */
const handleSuccessFile = (response: any, file: UploadFile) => {
	if (response.code === 200) {
		ElMessage.success('上传成功');
		valFileList.value.push(response.data.url);
		emit('update:modelValue', valFileList.value);
		return;
	} else {
		ElMessage.error(response.msg || '上传失败');
	}
};

const handleError = (error: any) => {
	ElMessage.error('上传失败');
};

/**
 * 删除图片
 */
function handleRemove(removeFile: UploadFile) {
	const filePath = removeFile.url;
	if (filePath) {
		valFileList.value = valFileList.value.filter((x) => x !== filePath);
		// 删除成功回调
		emit('update:modelValue', valFileList.value);
	}
}

/**
 * 限制用户上传文件的格式和大小
 */
function handleBeforeUpload(file: UploadRawFile) {
	if (file.size > props.uploadMaxSize) {
		ElMessage.warning('上传图片不能大于' + Math.trunc(props.uploadMaxSize / 1024 / 1024) + 'M');
		return false;
	}
	return true;
}

/**
 * 预览图片
 */
const previewImg: UploadProps['onPreview'] = (uploadFile: UploadFile) => {
	viewFileList.value = fileList.value.map((file) => file.url!);
	initialIndex.value = fileList.value.findIndex((file) => file.url === uploadFile.url);
	viewVisible.value = true;
};

/**
 * 关闭预览
 */
const closePreview = () => {
	viewVisible.value = false;
};
</script>
  <style lang="scss" scoped>
.hide {
	:deep(.el-upload--picture-card) {
		display: none;
	}
}

.show {
	:deep(.el-upload--picture-card) {
		display: flex;
	}
}
</style>
  